package org.codeanalyzer.util;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * Contains miscellaneous utility methods
 */
public class Utils
{

    /**
     * Extracts java files from zip archive into OS specific temp directory.
     * 
     * @param fileName
     *            the zip file name
     * @return the list of extracted java files
     */
    public static List<File> extractJavaFilesFromZip(String fileName) throws IOException
    {
        File zipFile = new File(fileName);
        File targetDir = new File(System.getProperty("java.io.tmpdir") + File.separator + "apianalyzer");

        unpackZipArchive(zipFile, targetDir);

        return listJavaFilesRecursively(targetDir);
    }

    /**
     * Unpacks zip archive into specified folder.
     * 
     * @param theFile
     *            the zip file
     * @param targetDir
     *            the directory to extract
     */
    public static void unpackZipArchive(File theFile, File targetDir) throws IOException
    {
        if ( !theFile.exists())
            throw new IOException(theFile.getAbsolutePath() + " does not exist");

        if ( !buildDirectory(targetDir))
            throw new IOException("Could not create directory: " + targetDir);

        ZipFile zipFile = new ZipFile(theFile);
        System.out.println("Extracting " + theFile.getAbsolutePath() + " to " + targetDir.getAbsolutePath());
        for(Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();)
        {
            ZipEntry entry = entries.nextElement();
            File file = new File(targetDir, File.separator + entry.getName());
            System.out.println(" unpacking " + entry.getName() + " ...");
            if ( !buildDirectory(file.getParentFile()))
            {
                throw new IOException("Could not create directory: " + file.getParentFile());
            }
            if ( !entry.isDirectory())
            {
                copyInputStream(zipFile.getInputStream(entry),
                    new BufferedOutputStream(new FileOutputStream(file)));
            }
            else
            {
                if ( !buildDirectory(file))
                {
                    throw new IOException("Could not create directory: " + file);
                }
            }
        }
        zipFile.close();
    }

    private static void copyInputStream(InputStream in, OutputStream out) throws IOException
    {
        byte[] buffer = new byte[1024];
        int len = in.read(buffer);
        while(len >= 0)
        {
            out.write(buffer, 0, len);
            len = in.read(buffer);
        }
        in.close();
        out.close();
    }

    private static boolean buildDirectory(File file)
    {
        return file.exists() || file.mkdirs();
    }

    /**
     * Returns all java files that reside under specified directory ant its
     * sub-directories
     * 
     * @param dir
     *            the target directory where to start looking for source files
     * @return
     */
    public static List<File> listJavaFilesRecursively(File dir)
    {
        List<File> sourceFiles = new ArrayList<File>();
        for(File file : dir.listFiles())
        {
            if (file.isDirectory())
            {
                sourceFiles.addAll(listJavaFilesRecursively(file));
            }
            else if (isJavaFile(file))
            {
                sourceFiles.add(file);
            }
        }
        return sourceFiles;
    }

    private static boolean isJavaFile(File file)
    {
        return file.getName().endsWith(".java");
    }

}
